package gatperdut.chato.core.room;

import gatperdut.chato.constants.CSConstantsMovement.Direction;
import gatperdut.chato.core.ChatoServer;
import gatperdut.chato.model.Chato.Room.Door;
import gatperdut.chato.model.Chato.Room.Room;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class ExitsController {

    private final ChatoServer chatoServer;

    private final Room room;

    private RoomController nRC;
    private RoomController eRC;
    private RoomController sRC;
    private RoomController wRC;
    private RoomController uRC;
    private RoomController dRC;

    private DoorController nDC;
    private DoorController eDC;
    private DoorController sDC;
    private DoorController wDC;
    private DoorController uDC;
    private DoorController dDC;

    public ExitsController( ChatoServer chatoServer, Room room ) {
        this.chatoServer = chatoServer;
        this.room = room;

        loadDoors();
    }

    private void loadDoors() {
        if ( getRoom().getDN() != null ) {
            setnDC( createDoor( getRoom().getDN() ) );
        }
        if ( getRoom().getDE() != null ) {
            seteDC( createDoor( getRoom().getDE() ) );
        }
        if ( getRoom().getDS() != null ) {
            setsDC( createDoor( getRoom().getDS() ) );
        }
        if ( getRoom().getDW() != null ) {
            setwDC( createDoor( getRoom().getDW() ) );
        }
        if ( getRoom().getDU() != null ) {
            setuDC( createDoor( getRoom().getDU() ) );
        }
        if ( getRoom().getDD() != null ) {
            setdDC( createDoor( getRoom().getDD() ) );
        }
    }

    private DoorController createDoor( Door door ) {
        if ( getChatoServer().getRoomHandler().getDoorToController().get( door ) == null ) {
            DoorController dc = new DoorController( getChatoServer(), door );
            getChatoServer().getRoomHandler().getDoorToController().put( door, dc );
            return dc;
        }
        else {
            return getChatoServer().getRoomHandler().getDoorToController().get( door );
        }
    }

    public Map<Direction, DoorController> getAdjacentDoorControllers() {
        Map<Direction, DoorController> dcs = new HashMap<Direction, DoorController>();
        if ( getnDC() != null ) {
            dcs.put( Direction.NORTH, getnDC() );
        }
        if ( geteDC() != null ) {
            dcs.put( Direction.EAST, geteDC() );
        }
        if ( getsDC() != null ) {
            dcs.put( Direction.SOUTH, getsDC() );
        }
        if ( getwDC() != null ) {
            dcs.put( Direction.WEST, getwDC() );
        }
        if ( getuDC() != null ) {
            dcs.put( Direction.UP, getuDC() );
        }
        if ( getdDC() != null ) {
            dcs.put( Direction.DOWN, getdDC() );
        }

        return dcs;
    }

    public DoorController getAdjacentDoorController( Direction d ) {
        switch ( d ) {
        case DOWN:
            return getdDC();
        case EAST:
            return geteDC();
        case NORTH:
            return getnDC();
        case SOUTH:
            return getsDC();
        case UP:
            return getuDC();
        case WEST:
            return getwDC();
        default:
            throw new IllegalArgumentException( "Getting adjacent door controller: invalid direction." );
        }
    }

    public Map<Direction, RoomController> getAdjacentRoomControllers() {
        Map<Direction, RoomController> rcs = new HashMap<Direction, RoomController>();
        if ( getnRC() != null ) {
            rcs.put( Direction.NORTH, getnRC() );
        }
        if ( geteRC() != null ) {
            rcs.put( Direction.EAST, geteRC() );
        }
        if ( getsRC() != null ) {
            rcs.put( Direction.SOUTH, getsRC() );
        }
        if ( getwRC() != null ) {
            rcs.put( Direction.WEST, getwRC() );
        }
        if ( getuRC() != null ) {
            rcs.put( Direction.UP, getuRC() );
        }
        if ( getdRC() != null ) {
            rcs.put( Direction.DOWN, getdRC() );
        }

        return rcs;
    }

    public RoomController getAdjacentRoomController( Direction d ) {
        switch ( d ) {
        case DOWN:
            return getdRC();
        case EAST:
            return geteRC();
        case NORTH:
            return getnRC();
        case SOUTH:
            return getsRC();
        case UP:
            return getuRC();
        case WEST:
            return getwRC();
        default:
            throw new IllegalArgumentException( "Getting adjacent room controller: invalid direction." );
        }
    }

    public String getExits() {
        Set<Entry<Direction, RoomController>> entriesRC = getAdjacentRoomControllers().entrySet();
        Map<Direction, DoorController> doorControllers = getAdjacentDoorControllers();

        if ( entriesRC.isEmpty() ) {
            return "Exits: none";
        }

        StringBuilder sb = new StringBuilder( "Exits: " );

        DoorController dc;
        for ( Entry<Direction, RoomController> entry : entriesRC ) {
            sb.append( entry.getKey().getAsString() );
            dc = doorControllers.get( entry.getKey() );
            if ( dc != null ) {
                if ( dc.getDoor().isOpen() ) {
                    sb.append( " (open " + dc.getDoor().getSingleWord() + ") " );
                }
                else {
                    sb.append( " (closed " + dc.getDoor().getSingleWord() + ") " );
                }
            }
            else {
                sb.append( " " );
            }
        }

        return sb.toString();
    }

    // TODO this probably should be somewhere else. room controllers need to
    // know nothing about CDO.
    public String getAdjacentRoomCDOID( Direction d ) {
        RoomController roomController = getAdjacentRoomController( d );
        if ( roomController == null ) {
            return "";
        }
        else {
            return roomController.getRoom().cdoID().toURIFragment();
        }
    }

    public DoorController getnDC() {
        return nDC;
    }

    public void setnDC( DoorController nDC ) {
        this.nDC = nDC;
    }

    public DoorController geteDC() {
        return eDC;
    }

    public void seteDC( DoorController eDC ) {
        this.eDC = eDC;
    }

    public DoorController getsDC() {
        return sDC;
    }

    public void setsDC( DoorController sDC ) {
        this.sDC = sDC;
    }

    public DoorController getwDC() {
        return wDC;
    }

    public void setwDC( DoorController wDC ) {
        this.wDC = wDC;
    }

    public DoorController getuDC() {
        return uDC;
    }

    public void setuDC( DoorController uDC ) {
        this.uDC = uDC;
    }

    public DoorController getdDC() {
        return dDC;
    }

    public void setdDC( DoorController dDC ) {
        this.dDC = dDC;
    }

    public RoomController getnRC() {
        return nRC;
    }

    public void setnRC( RoomController nRC ) {
        this.nRC = nRC;
    }

    public RoomController geteRC() {
        return eRC;
    }

    public void seteRC( RoomController eRC ) {
        this.eRC = eRC;
    }

    public RoomController getsRC() {
        return sRC;
    }

    public void setsRC( RoomController sRC ) {
        this.sRC = sRC;
    }

    public RoomController getwRC() {
        return wRC;
    }

    public void setwRC( RoomController wRC ) {
        this.wRC = wRC;
    }

    public RoomController getuRC() {
        return uRC;
    }

    public void setuRC( RoomController uRC ) {
        this.uRC = uRC;
    }

    public RoomController getdRC() {
        return dRC;
    }

    public void setdRC( RoomController dRC ) {
        this.dRC = dRC;
    }

    public ChatoServer getChatoServer() {
        return chatoServer;
    }

    public Room getRoom() {
        return room;
    }

}
